Set up and connect Azure OpenAI

To use the AI services in Aeneis, you must set up Azure OpenAI with certificate-based Entra ID authentication accordingly.

Requirements

  • Azure Entra ID with authorization to create app registrations and role mapping on the Azure OpenAI resource

  • Azure OpenAI resources provided (region, deployments/models, quota)

  • OpenSSL on the system on which Aeneis is running

  • Use of the corresponding certificate files in Entra ID and the application.yml in the Aeneis application directory

  • Aeneis service account with read access to the certificate files

Set up app registration in Entra ID

To use AI services in Aeneis, set up your app registration in Entra ID accordingly.

Instructions:

  1. Create a new app registration

  2. Give the app registration a name

  3. Make sure that the option Accounts in this organizational directory only is selected under Supported account types

  4. Make a note of the Directory (tenant) ID and application (client) ID

Generate certificate files

To connect the OpenAI services, create a certificate with an SSL tool, e.g. OpenSSL. Use a script to create the following necessary files.

  • aoai-key.enc.pem (encrypted private key, PKCS#8)
  • aoai-cert.csr (CSR)
  • aoai-cert.pem (self-signed, for Entra upload)
  • aoai-key.pass (passphrase, without newline)
  • aoai-cert.cer (Base64 from PEM), if the Azure portal prefers CER files

Create certificate files via PowerShell

Create a script in PowerShell according to the following example and execute it to generate the certificate files.

Copy
Example: PowerShell
# Generates encrypted private key (PKCS#8), CSR, self-signed certificate, and passphrase file.
$ErrorActionPreference = "Stop"

# --- Paths ---
# >>>  CUSTOMIZE: Base directories for AOAI assets and passphrase file.
$AoaiDir  = "C:\Users\PUBLIC\aeneis\aoai"
$PassDir  = "C:\Users\PUBLIC\aeneis\pass"

# >>> CUSTOMIZE: CUSTOMIZE: File names (if desired)
$KeyEnc   = Join-Path $AoaiDir "aoai-key.enc.pem"
$Csr      = Join-Path $AoaiDir "aoai-cert.csr"
$CertPem  = Join-Path $AoaiDir "aoai-cert.pem"
$CertCer  = Join-Path $AoaiDir "aoai-cert.cer"   # (optional) CER from PEM
$ExtCnf   = Join-Path $AoaiDir "ext.cnf"
$PassFile = Join-Path $PassDir "aoai-key.pass"

$CreatedPaths = @()

if (-not (Get-Command openssl -ErrorAction SilentlyContinue)) {
  throw "OpenSSL was not found. Please install OpenSSL or place openssl.exe in the PATH."
}

New-Item -ItemType Directory -Force $AoaiDir | Out-Null
New-Item -ItemType Directory -Force $PassDir | Out-Null

# --- Request passphrase ---
# >>> CUSTOMIZE: Enforce minimum length/policy as needed
$sec = Read-Host "Please enter passphrase for aoai-key.enc.pem" -AsSecureString
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
try {
  $plain = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
} finally {
  if ($bstr -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) }
}
if ([string]::IsNullOrWhiteSpace($plain)) { throw "No passphrase entered." }

# 1) Encrypted Private Key (RSA-3072, AES-256)
if (-not (Test-Path $KeyEnc)) {
  # >>> CUSTOMIZE (optional): rsa_keygen_bits (z.B. 4096)
  & openssl genpkey -algorithm RSA -aes256 -pkeyopt rsa_keygen_bits:3072 -out "$KeyEnc" -pass pass:$plain
  if (Test-Path $KeyEnc) { $CreatedPaths += $KeyEnc }
}

# 2) CSR
if (-not (Test-Path $Csr)) {
  # >>> CUSTOMIZE: DN (Company/Location/CN)
  & openssl req -new -key "$KeyEnc" -out "$Csr" `
    -subj "/C=XX/ST=STATE/O=Example Company/CN=EXAMPLE-CLIENT" `
    -passin pass:$plain
  if (Test-Path $Csr) { $CreatedPaths += $Csr }
}

# 3) Extensions file
@"
[ext]
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = clientAuth
"@ | Set-Content -Path "$ExtCnf" -Encoding ASCII
if (Test-Path $ExtCnf) { $CreatedPaths += $ExtCnf }

# 4) Self-signed certificate
if (-not (Test-Path $CertPem)) {
  # >>> CUSTOMIZE: Validity days
  & openssl x509 -req -days 365 -in "$Csr" -signkey "$KeyEnc" -out "$CertPem" -extfile "$ExtCnf" -extensions ext -passin pass:$plain
  if (Test-Path $CertPem) { $CreatedPaths += $CertPem }
}

# 4a) Generate CER from PEM – for Entra upload
if ((Test-Path $CertPem) -and -not (Test-Path $CertCer)) {
  & openssl x509 -in "$CertPem" -outform PEM -out "$CertCer"
  if (Test-Path $CertCer) { $CreatedPaths += $CertCer }
  #  Alternative (DER format):
  # & openssl x509 -in "$CertPem" -outform DER -out "$CertCer"
}

# 5) Passphrase file
# >>> Note: Contains plaintext passphrase – restrict NTFS ACLs!
if (-not (Test-Path $PassFile)) {
  [System.IO.File]::WriteAllText($PassFile, $plain, [System.Text.Encoding]::ASCII)
  if (Test-Path $PassFile) { $CreatedPaths += $PassFile }
}

# Clean up
$plain = $null

# Output only paths of newly created files
$CreatedPaths | ForEach-Object { Write-Host $_ }

Create certificate files via Bash for Linux

Create a script in Bash according to the following example and execute it to generate the certificate files.

Copy
Example: Bash
#!/usr/bin/env bash
set -euo pipefail

# --- Paths ---
# >>> CUSTOMIZE: Base directories for AOAI assets and passphrase file.
AOAI_DIR="${HOME}/aeneis/aoai"
PASS_DIR="${HOME}/aeneis/pass"

# >>> CUSTOMIZE: CUSTOMIZE: File names (if desired)
KEY_ENC="${AOAI_DIR}/aoai-key.enc.pem"
CSR="${AOAI_DIR}/aoai-cert.csr"
CERT_PEM="${AOAI_DIR}/aoai-cert.pem"
CERT_CER="${AOAI_DIR}/aoai-cert.cer"   # (optional) CER from PEM
EXT_CNF="${AOAI_DIR}/ext.cnf"
PASS_FILE="${PASS_DIR}/aoai-key.pass"

declare -a CREATED

command -v openssl >/dev/null 2>&1 || { echo "OpenSSL not found:"; exit 1; }

mkdir -p "$AOAI_DIR" "$PASS_DIR"

# ---  Request passphrase ---
# >>> CUSTOMIZE: Minimum length/policy as required
read -r -s -p "Please enter passphrase for aoai-key.enc.pem:" PLAIN
echo
[[ -z "${PLAIN// }" ]] && { echo "No passphrase entered."; exit 1; }

# 1) Encrypted Private Key (RSA-3072, AES-256-CBC)
if [[ ! -f "$KEY_ENC" ]]; then
  # >>> CUSTOMIZE (optional): rsa_keygen_bits (z.B. 4096)
  openssl genpkey -algorithm RSA -aes-256-cbc -pkeyopt rsa_keygen_bits:3072 \
    -out "$KEY_ENC" -pass pass:"$PLAIN"
  [[ -f "$KEY_ENC" ]] && CREATED+=("$KEY_ENC")
fi

# 2) CSR
if [[ ! -f "$CSR" ]]; then
  # >>> CUSTOMIZE: DN (Company/Location/CN)
  openssl req -new -key "$KEY_ENC" -out "$CSR" \
    -subj "/C=XX/ST=STATE/O=Example Company/CN=EXAMPLE-CLIENT" \
    -passin pass:"$PLAIN"
  [[ -f "$CSR" ]] && CREATED+=("$CSR")
fi

# 3) Extensions file
cat > "$EXT_CNF" <<'EOF'
[ext]
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = clientAuth
EOF
[[ -f "$EXT_CNF" ]] && CREATED+=("$EXT_CNF")

# 4) Self-signed certificate
if [[ ! -f "$CERT_PEM" ]]; then
  # >>> CUSTOMIZE: Validity days
  openssl x509 -req -days 365 -in "$CSR" -signkey "$KEY_ENC" -out "$CERT_PEM" \
    -extfile "$EXT_CNF" -extensions ext -passin pass:"$PLAIN"
  [[ -f "$CERT_PEM" ]] && CREATED+=("$CERT_PEM")
fi

# 4a) Generate CER from PEM – for Entra upload
if [[ -f "$CERT_PEM" && ! -f "$CERT_CER" ]]; then
  openssl x509 -in "$CERT_PEM" -outform PEM -out "$CERT_CER"
  [[ -f "$CERT_CER" ]] && CREATED+=("$CERT_CER")
  # Alternative (DER format):
  # openssl x509 -in "$CERT_PEM" -outform DER -out "$CERT_CER"
fi

# 5) Passphrase file
# >>> Note: Contains plaintext passphrase – restrict file permissions!
if [[ ! -f "$PASS_FILE" ]]; then
  umask 0077
  printf "%s" "$PLAIN" > "$PASS_FILE"
  [[ -f "$PASS_FILE" ]] && CREATED+=("$PASS_FILE")
fi

unset PLAIN

# Only output paths of newly created files
for p in "${CREATED[@]:-}"; do
  echo "$p"
done

Upload public certificate in Entra ID

To log in via ClientCertificateCredential, you must upload the public certificate in Entra ID in the app registration.

Instructions:

  1. In Microsoft Entra ID, open the Certificates & secrets section of the app registration that you use in Aeneis for the Azure Open AI service

  2. In the Certificates tab, use the Upload certificate button to upload the PEM file that you have generated in your SSL tool

Set up role-based access control on the Azure OpenAI resource

Assign roles to the app registration (service principal) on the Azure OpenAI resource under Access Control (IAM) via Add role assignment:

  • Cognitive Services OpenAI User

  • Cognitive Services OpenAI Contributor

extend application.yml

To set up Azure OpenAI on the Aeneis side, extend the application.yml in the application directory as in the following example.

Note: Adjust the entries in the example according to your configuration.

Copy
Example: application.yml
azure-openai:
tenant-id: YOUR_TENANT_ID
client-id: YOUR_CLIENT_ID
endpoint: https://<RESOURCE_NAME>.services.ai.azure.com/
  gpt-5-mini: gpt-5-mini
  gpt-4o: gpt-4o
  pem-cert-file: C:\Users\bob\aeneis\aoai\aoai-cert.pem # &gt;&gt;&gt; CUSTOMIZE
  pem-key-file: C:\Users\bob\aeneis\aoai\aoai-key.enc.pem # &gt;&gt;&gt; CUSTOMIZE
  pem-passphrase-file: C:\Users\bob\aeneis\aoai\pass\aoai-key.pass # &gt;&gt;&gt; CUSTOMIZE
  billing:
    models:
      gpt-5-mini: {inputPricePerMillionEur: 0.22, outputPricePerMillionEur: 1.74}
      gpt-4o: {inputPricePerMillionEur: 2.18, outputPricePerMillionEur: 8.7}

Important notes:

  • The paths to the certificate data must be exact.
  • The Aeneis service account requires read access to all three certificate files.
  • If you are using Linux, specify paths with / (e.g. /opt/aeneis/aoai/aoai-cert.pem).

Set AI credit limit

In Aeneis, AI credits represent a variable quota of AI requests that is renewed and reset monthly. If you use Aeneis On-Premise, you can set a monthly upper limit for AI requests in the ServerAdministration Preferences via the AI credits property.

You can view the current usage of AI credits via Help in the Portal header.

Perform function test

Once you have completed the setup, you can carry out a function test.

Instructions:

  1. Start Aeneis

  2. Open the chatbot in the Portal and ask a question

Troubleshooting

If one of the following symptoms occurs, you can remedy the situation as follows:

Symptom

Cause

Action

401 invalid_client

Public certificate not uploaded/differently uploaded

Upload aoai-cert.pem or aoai-cert.cer in Entra ID again; check thumbprint/expiration

403 Forbidden

Role missing

Assign OpenAI User and OpenAI Contributor to resource

404 Deployment not found

Incorrect deployment name

Check names under Deployments and adapt application.yml

TLS/Key error

Incorrect format or passphrase

Ensure PKCS#8, check paths, aoai-key.pass without newline

No streaming

Proxy/Firewall/Endpoint

*enable .services.ai.azure.com; check TLS inspection

Locally ok, as a service not

File rights

Set read access of the service account to all 3 files

Portal only accepts .cer

PEM is rejected

create .cer from PEM (see step 3 "4a") and upload